package com.openlogic.logic.service.logic.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Inject;
import org.noear.solon.cloud.CloudClient;
import org.noear.solon.data.annotation.Tran;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.openlogic.api.logic.entity.RuleModelDeploy;
import com.openlogic.common.core.enums.DictEnum;
import com.openlogic.common.core.exception.ServiceException;
import com.openlogic.common.core.expression.Element;
import com.openlogic.common.core.utils.DateUtils;
import com.openlogic.common.core.web.domain.model.LoginUser;
import com.openlogic.common.logic.constants.ExecConstants;
import com.openlogic.common.logic.constants.NodeConstants;
import com.openlogic.common.logic.constants.RuleConstants;
import com.openlogic.common.logic.constants.RuleTypeConstants;
import com.openlogic.common.logic.event.RuleExecEventModel;
import com.openlogic.common.logic.event.RuleExecEventPublisher;
import com.openlogic.common.logic.node.enums.NodeExecEnums;
import com.openlogic.common.logic.node.enums.ParseTypeEnums;
import com.openlogic.common.logic.node.factory.NodeExecFactory;
import com.openlogic.common.logic.node.factory.NodeParseFactory;
import com.openlogic.common.logic.node.parse.BaseParseHandler;
import com.openlogic.common.logic.run.ExecRuleHandler;
import com.openlogic.common.logic.utils.ClobConvertUtils;
import com.openlogic.common.logic.utils.FuncLibExpreUtils;
import com.openlogic.common.security.utils.SecurityUtil;
import com.openlogic.logic.mapper.logic.RuleModelDeployMapper;
import com.openlogic.logic.service.logic.RuleModelDeployService;
import com.openlogic.logic.service.logic.RuleModelService;

import net.sf.json.JSONArray;

/**
* @ClassName: RuleModelDeployServiceImpl
* @Description: 规则模型ServiceImpl
* @author weiyongpeng
* @date 2024年7月14日 上午10:42:56
 */
@Component
public class RuleModelDeployServiceImpl implements RuleModelDeployService{
	
	private static final Logger logger = LoggerFactory.getLogger(RuleModelDeployServiceImpl.class);
	
	@Inject
	private RuleModelDeployMapper ruleModelDeployMapper;
	
	@Inject
	private RuleModelService ruleModelService;
	
	/**
	 * 实现ApplicationEventPublisher用于发布事件
	 */
	private RuleExecEventPublisher applicationEventPublisher = new RuleExecEventPublisher();

	@Override
	public List<RuleModelDeploy> findRuleDeployList(RuleModelDeploy model) {
		// 封装参数
		Map<String, Object> params = new HashMap<>();
		setParams(params,model);
		return ruleModelDeployMapper.selectRuleDeployList(params);
	}

	/**
	* 描述：设置参数
	* @Title: setParams
	* @author weiyongpeng
	* @date  2024年7月14日 上午10:22:46
	 */
	private void setParams(Map<String, Object> params, RuleModelDeploy model) {
		if (!Objects.isNull(model) && StringUtils.isNotBlank(model.getRuleModelKey())) {
			params.put("ruleModelKey", model.getRuleModelKey());
		}
		if (!Objects.isNull(model) && StringUtils.isNotBlank(model.getRuleModelName())) {
			params.put("ruleModelName", model.getRuleModelName());
		}
	}

	@Override
	public RuleModelDeploy findRuleDeployById(RuleModelDeploy ruleModelDeploy) {
		return ruleModelDeployMapper.selectOneById(ruleModelDeploy.getId());
	}

	@Override
	public int updateRuleModel(RuleModelDeploy ruleModelDeploy) {
		return ruleModelDeployMapper.update(ruleModelDeploy);
	}
	
	@Override
	public int saveRuleModel(RuleModelDeploy ruleModelDeploy) {
		return ruleModelDeployMapper.insert(ruleModelDeploy);
	}

	@Override
	@Tran
	public int save(RuleModelDeploy ruleModelDeploy,String resValue) {

		Date nowDate = DateUtils.getNowDate();
		LoginUser loginUser = SecurityUtil.getLoginUser();
		// 如果前端传递了版本号，则是新增版本，否则就是修改第一次创建规则/修改规则
		if (ruleModelDeploy.getRuleModelVersion() == null || ("null").equals(ruleModelDeploy.getRuleModelVersion()) || ("").equals(ruleModelDeploy.getRuleModelVersion())) {
			// 查询规则信息，根据主键ID
			RuleModelDeploy modelTree = findRuleDeployById(ruleModelDeploy);
			if (modelTree != null) { // 存在-修改
				modelTree.setRuleModelName(ruleModelDeploy.getRuleModelName());
				modelTree.setRuleModelValue(ruleModelDeploy.getRuleModelValue());
				modelTree.setRuleRawValue(ruleModelDeploy.getRuleRawValue());
				modelTree.setRuleResValue(ruleModelDeploy.getRuleModelValue());
				modelTree.setUpdateBy(String.valueOf(loginUser.getUserid()));
				modelTree.setUpdateTime(nowDate);
				ruleModelDeploy.setDelFlag(DictEnum.DEL_FLAG.OK.getValue());
				updateRuleModel(modelTree);
			} else { // 不存在-新增
				ruleModelDeploy.setId("FL" + DateUtils.getNowDate().getTime() + "");
				ruleModelDeploy.setRuleModelKey("key_" + ruleModelDeploy.getId());
				ruleModelDeploy.setRuleModelVersion("1");
				ruleModelDeploy.setRuleResValue(resValue);
				ruleModelDeploy.setCreateTime(nowDate);
				ruleModelDeploy.setCreateBy(String.valueOf(loginUser.getUserid()));
				ruleModelDeploy.setUpdateTime(nowDate);
				ruleModelDeploy.setStatus(RuleConstants.MODEL_STS_NOT_ENABLE);
				ruleModelDeploy.setRuleType(RuleTypeConstants.ruleflow.getCode()); // 决策流
				ruleModelDeploy.setDelFlag(DictEnum.DEL_FLAG.OK.getValue());
				saveRuleModel(ruleModelDeploy);
			}
		} else { // 新增版本
			ruleModelDeploy.setId(new Date().getTime() + "");
			ruleModelDeploy.setRuleModelVersion((getMaxVersionByKey(ruleModelDeploy.getRuleModelKey()) + 1) + "");
			ruleModelDeploy.setCreateTime(nowDate);
			ruleModelDeploy.setUpdateTime(nowDate);
			ruleModelDeploy.setStatus(RuleConstants.MODEL_STS_NOT_ENABLE);
			ruleModelDeploy.setCreateBy(String.valueOf(loginUser.getUserid()));
			ruleModelDeploy.setDelFlag(DictEnum.DEL_FLAG.OK.getValue());
			saveRuleModel(ruleModelDeploy);
		}
		
		return 0;
	}

	private int getMaxVersionByKey(String ruleModelKey) {
		return ruleModelDeployMapper.getMaxVersionByKey(ruleModelKey);
	}

	@Override
	public boolean updateStatus(RuleModelDeploy ruleModelDeploy) {
		try {
			ruleModelDeploy.setUpdateBy(String.valueOf(SecurityUtil.getUserId()));
			ruleModelDeploy.setUpdateTime(DateUtils.getNowDate());
			if(ruleModelDeployMapper.updateStatus(ruleModelDeploy) > 0) {
				return true;
			}
			return false;
		} catch (Exception e) {
			logger.error("修改状态失败：{}", e);
			throw new ServiceException("修改状态失败,请联系开发人员检查");
		}
	}

	@Override
	public boolean delete(String id) {
		try {
			if(ruleModelDeployMapper.delete(id) > 0) {
				return true;
			}
			return false;
		} catch (Exception e) {
			logger.error("删除失败：{}", e);
			throw new ServiceException("删除失败,请联系开发人员检查");
		}
	}

	@Override
	public List<RuleModelDeploy> findRuleDeployByParams(Map<String, Object> params) {
		return ruleModelDeployMapper.findRuleModelByParams(params);
	}

	@Override
	public List<Map<String, Object>> findRuleExecuateInfoById(String id) {
		return ruleModelDeployMapper.findRuleExecInfoById(id);
	}

	@Override
	public String execuateRule(String datas, String id, String operateNo) {
		Date nowDate = DateUtils.getNowDate();
		RuleExecEventModel execLog = new RuleExecEventModel();
		Date execStartDate = nowDate;
		String resultJson = "";
		String ruleName = "";
		try {
			String dataInfo = datas;
			// 规则id
			List<Map<String, Object>> ruleInfo = this.findRuleExecuateInfoById(id);
			// 规则图里数据 json
			String jsonStr = "";
			// 将规则变量拆分成Map结构
			Map<String,Object> ruleAttrMap = new HashMap<>();
			for (Map<String, Object> map : ruleInfo) {
				if(map.get("jsonStr") != null && (jsonStr == null || jsonStr.equals(""))) {
					jsonStr = ClobConvertUtils.clob2String(map.get("jsonStr"));
				}
				if(map.get("ruleModelName") != null && (ruleName == null || ruleName.equals(""))) {
					// 获取规则名称
					ruleName = map.get("ruleModelName").toString();
				}
				ruleAttrMap.put(map.get("modelIdentify").toString(), map.get("name").toString());
			}
			// 设置日志信息，并发布事件
			String logId = String.valueOf(CloudClient.id().generate());
			execLog.setLogId(logId);
			execLog.setOperateNo(operateNo);
			execLog.setOperateDate(DateUtils.formatDate(execStartDate, DateUtils.YYYY_MM_DD));
			execLog.setExecStartTime(execStartDate);
			execLog.setReqParam(dataInfo);
			execLog.setRuleId(id);
			execLog.setRuleName(ruleName);
			
			// 第一次解析
			BaseParseHandler baseParseHandler = NodeParseFactory.getInvokeStrategyMap(ParseTypeEnums.DEFAULT_INFO.getParsetype());
			String resValue = baseParseHandler.getResValue(jsonStr);
			JSONObject resJson = JSON.parseObject(resValue);
			resJson.put("ruleId","");
			resValue = resJson.toString();
			StringBuffer reason = new StringBuffer();
			logger.info("resValue={}", resValue);
			logger.info("dataInfo={}", dataInfo);
			logger.info("ruleAttrMap={}", ruleAttrMap.toString());
			// 执行
			ExecRuleHandler execRuleHandler = NodeExecFactory.getInvokeStrategyMap(NodeExecEnums.DEFAULT_NODE.getCode());
			resultJson = execRuleHandler.runAndGetResult(resValue, dataInfo, reason, ruleAttrMap);
			JSONObject resJsonNew = JSON.parseObject(resultJson);
			logger.info("resultJsonBefore={}",resultJson);
			logger.info("reason={}", reason);
			// 调整resultJson结构
			if(resultJson != null && StringUtils.isNotBlank(resultJson)) {
				resultJson = execRuleHandler.changeEveryNodeList(resultJson,reason);
			}
			logger.info("resultJsonAfter={}",resultJson);
			resJsonNew.remove("everyNodeList");
			// 2024-10-21暂时移除areaInfo
			resJsonNew.remove("areaInfo");
			resultJson = resJsonNew.toString();
			
			execLog.setStatus(ExecConstants.SUCCESS);
			execLog.setRepParam(resultJson);
			Date execEndDate = DateUtils.getNowDate();
			execLog.setExecEndTime(execEndDate);
			execLog.setExecTime((execEndDate.getTime()-execStartDate.getTime()));

			// 事件发布-规则执行完毕后发布事件，附加功能可在监听处实现，解耦
			applicationEventPublisher.publishLogListener(execLog);
		} catch (Exception e) {
			logger.error("执行错误：{}", e);
			Date execEndDate = DateUtils.getNowDate();
			execLog.setExecEndTime(execEndDate);
			execLog.setExecTime((execEndDate.getTime()-execStartDate.getTime()));
			execLog.setErrorMsg(e.getMessage());
			execLog.setStatus(ExecConstants.ERROR);
			// 事件发布-规则执行完毕后发布事件，附加功能可在监听处实现，解耦
			applicationEventPublisher.publishLogListener(execLog);
			throw new ServiceException("执行错误");
		}
		return resultJson;
	}

	@SuppressWarnings("unchecked")
	@Override
	public List<Map<String, Object>> checkFormulae(Map<String, Object> params) throws Exception {
		// 1、定义返回值
		Map<String, Object> res = new HashMap<String, Object>(); 	// 结果
		Map<String, Object> error = new HashMap<String, Object>(); 	// 错误
		StringBuilder ruleResovle = new StringBuilder(); 			// 解析后的公式
		// 2、获取参数
		String expression = params.get("expression").toString();
		String varJson = Optional.ofNullable(params.get("var").toString()).orElse(null);
		// 2.1、参数转化
		List<Map<String,Object>> list = new ArrayList<>();
		if(varJson != null) {
			list = JSONObject.parseObject(varJson, List.class);
		}
		// 3、校验解析
		List<Element> splitExprs = FuncLibExpreUtils.split(expression,list);
		Map<String, Object> result = FuncLibExpreUtils.compile(splitExprs);
		List<Map<String, Object>> resultList = FuncLibExpreUtils.validateRuleFunc(res, error, ruleResovle, result);
		return resultList;
	}

	@Override
	public List<Map<String,Object>> findRuleDeployModelInner(Map<String, Object> params) {
		List<RuleModelDeploy> list = ruleModelDeployMapper.findRuleModelInner(params);
		List<Map<String,Object>> resltList = new ArrayList<>();
		
		for (int i = 0; i < list.size(); i++) {
			String ruleResValue = Optional.ofNullable(list.get(i).getRuleResValue()).orElse("");
			RuleModelDeploy ruleModelDeploy = list.get(i);
			Map<String, Object> param = new HashMap<>();
			if (StringUtils.isNotBlank(ruleResValue)) {
				// 解析入参，获取规则链中用到的入参，且类型为输入变量的
				JSONObject ruleJsonObject = JSON.parseObject(ruleResValue);
				// 获取nodes数据集
				JSONObject nodeInfoJsonObject = JSON.parseObject(ruleJsonObject.get(NodeConstants.NODE_INFO).toString());
				// 获取lines数据集
				JSONObject lineInfoJsonObject = JSON.parseObject(ruleJsonObject.get(NodeConstants.LINE_INFO).toString());
				
				JSONArray nodeArray = net.sf.json.JSONObject.fromObject(nodeInfoJsonObject.toString()).getJSONArray("Value");
				JSONArray lineArray = net.sf.json.JSONObject.fromObject(lineInfoJsonObject.toString()).getJSONArray("Value");
				for(int k=0,nodeArraylength=nodeArray.size();k<nodeArraylength;k++) {
					if(StringUtils.isNotBlank(JSON.parseArray(nodeArray.get(k).toString()).get(3).toString())) {
						ruleModelDeploy = getValue(JSONObject.parseObject(JSON.parseArray(nodeArray.get(k).toString()).get(3).toString()).toString(),ruleModelDeploy,param);
					}
				}
				for(int j=0,lineArraylength=lineArray.size();j<lineArraylength;j++) {
					if(StringUtils.isNotBlank(JSON.parseArray(lineArray.get(j).toString()).get(5).toString())) {
						ruleModelDeploy = getValue(JSONObject.parseObject(JSON.parseArray(lineArray.get(j).toString()).get(5).toString()).toString(),ruleModelDeploy,param);
					}
				}
			}
			resltList.add(param);
		}
		return resltList;
	}

	
	private static RuleModelDeploy getValue(String value, RuleModelDeploy ruleModelDeploy,Map<String, Object> param) {
		JSONObject jsonObject = JSON.parseObject(value);
		param.put("id", ruleModelDeploy.getId());
		param.put("ruleModelName", ruleModelDeploy.getRuleModelName());
		param.put("ruleModeKey", ruleModelDeploy.getRuleModelKey());
		if(ruleModelDeploy.getRuleModelIdentify() != null && ruleModelDeploy.getRuleModelName() != null) {
			String[] ruleModelIdentify = ruleModelDeploy.getRuleModelIdentify().split(","); // 决策标识
			String[] name = ruleModelDeploy.getRuleModelName().split(","); // 决策名称
			Set<String> identifySbf = new LinkedHashSet<String>();
			Set<String> nameSbf = new LinkedHashSet<String>();
			for (Object tempArray : jsonObject.entrySet()) {
				int tempLength = tempArray.toString().indexOf("=");
				String tempValue = tempArray.toString().substring(tempLength + 1);
				for (int i = 0; i < ruleModelIdentify.length; i++) {
					if(tempValue.contains(ruleModelIdentify[i])) {
						identifySbf.add(ruleModelIdentify[i]);
						nameSbf.add(name[i]);
					}
				}
			}
			ruleModelDeploy.setRuleModelName (StringUtils.join(nameSbf,","));
			ruleModelDeploy.setRuleModelIdentify(StringUtils.join(identifySbf,","));
			param.put("varName", StringUtils.join(nameSbf,","));
			param.put("varIdentify", StringUtils.join(identifySbf,","));
		}
		return ruleModelDeploy;
	}

	@Override
	public List<RuleModelDeploy> findRuleDeployModel(Map<String, Object> params) {
		List<RuleModelDeploy> list = ruleModelDeployMapper.findRuleModelInner(params);
		return list;
	}
}
